package com.lzw.breezeNovel.webApp.service.impl.Ai;


import com.alibaba.dashscope.aigc.generation.Generation;
import com.alibaba.dashscope.aigc.generation.GenerationParam;

import com.alibaba.dashscope.aigc.videosynthesis.VideoSynthesis;
import com.alibaba.dashscope.aigc.videosynthesis.VideoSynthesisParam;

import com.alibaba.dashscope.common.Message;
import com.alibaba.dashscope.common.Role;

import com.google.common.collect.Lists;
import com.lzw.breezeNovel.common.exception.BaseException;
import com.lzw.breezeNovel.common.login.LoginUser;
import com.lzw.breezeNovel.common.login.LoginUserHolder;
import com.lzw.breezeNovel.common.result.ResultCodeEnum;
import com.lzw.breezeNovel.model.entity.pojo.Ai.AiAnswer;
import com.lzw.breezeNovel.model.entity.pojo.Ai.AiVideo;
import com.lzw.breezeNovel.model.entity.pojo.user.UserInfo;
import com.lzw.breezeNovel.model.entity.query.Ai.ImageQuery;
import com.lzw.breezeNovel.model.entity.query.Ai.VideoQuery;
import com.lzw.breezeNovel.webApp.config.DashScopeConfig;
import com.lzw.breezeNovel.webApp.mapper.Ai.AiAnswerMapper;
import com.lzw.breezeNovel.webApp.mapper.Ai.AiVideoMapper;
import com.lzw.breezeNovel.webApp.mapper.user.UserInfoMapper;
import com.lzw.breezeNovel.webApp.service.Ai.AiSercive;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.ai.image.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;


/**
 * @author 清风明月
 * @Package com.lzw.breezeNovel.webApp.service.impl.Ai
 * @date 2025/3/19
 * @description 人工智能
 */
@Slf4j
@Service
@SuppressWarnings("all")
public class AiServiceImpl implements AiSercive {

    /**
     * 注入配置文件
     */
    @Autowired
    private DashScopeConfig dashScopeConfig;
    /**
     * 获取用户的提提问题
     */
    @Autowired
    private AiAnswerMapper aiAnswerMapper;
    /**
     * 注入用户mapper
     */
    @Autowired
    private UserInfoMapper userInfoMapper;
    /**
     * 注入redis
     */
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 注入保存视频
     */
    @Autowired
    private AiVideoMapper aiVideoMapper;

    /**
     * 注入图片模型
     */
    @Autowired
    private  ImageModel imageModel;

    /**
     * 会话历史记录
     */
    private List<Message> conversationHistory = Lists.newArrayList();


    /**
     * 多轮对话
     *
     * @param userContent 用户输入的内容
     * @return 模型回复的内容
     */
    @Override
    public String chat(String userContent) {
        try {
            // 获取当前用户id
            Long userId = getUserId();

            // 从缓存中加载对话历史
            loadConversationHistoryFromCache(userId);

            // 构造用户消息
            Message userMessage = Message.builder()
                    .role(Role.USER.getValue())
                    .content(userContent)
                    .build();

            // 将用户消息添加到对话历史中
            conversationHistory.add(userMessage);

            // 构造请求参数，包含对话历史
            GenerationParam generationParam = GenerationParam.builder()
                    .apiKey(dashScopeConfig.getApiKey())
                    .model(dashScopeConfig.getModelText())
                    .messages(conversationHistory)
                    .resultFormat(GenerationParam.ResultFormat.MESSAGE)
                    .build();

            // 调用模型获取回复
            Generation generation = new Generation();
            String botResponse = generation.call(generationParam).getOutput().getChoices().get(0).getMessage().getContent();

            // 构造模型回复消息
            Message botMessage = Message.builder()
                    .role(Role.ASSISTANT.getValue())
                    .content(botResponse)
                    .build();

            // 将模型回复添加到对话历史中
            conversationHistory.add(botMessage);

            // 保存对话记录到数据库
            saveConversationHistory(userContent, botResponse, userId);

            return botResponse;

        } catch (Exception e) {
            log.error("调用模型失败", e);
            throw new BaseException(ResultCodeEnum.SERVICE_ERROR);
        }
    }

    /**
     * 生成图片
     * @param userContent
     * @return
     */
    @Override
    public List<String> img(@NotNull ImageQuery image) {
        // 使用ImageOptionsBuilder构建ImageOptions对象，设置图片生成的参数
        ImageOptions options = ImageOptionsBuilder.builder()
                .withWidth(image.getWidth()) // 设置生成图片的宽度
                .withHeight(image.getHeight()) // 设置生成图片的高度
                .withModel(dashScopeConfig.getModelImage()) // 设置使用的模型名称
                .withN(4) // 设置生成图片的数量为4张
                .build();

        // 创建一个ImagePrompt对象，传入用户输入的内容和图片生成选项
        String prompts = "图片的描述: " +  image.getContent() + " 图片的类型: " +  image.getType();
        ImagePrompt prompt = new ImagePrompt(prompts, options);

        // 调用imageModel的call方法，传入prompt，获取图片生成的响应
        ImageResponse response = imageModel.call(prompt);

        // 获取响应中的图片生成结果列表
        List<ImageGeneration> results = response.getResults();

        // 创建一个列表，用于存储生成图片的URL
        List<String> imageUrls = new ArrayList<>();

        // 检查结果列表是否不为空
        if (!results.isEmpty()) {
            // 遍历结果列表中的每个ImageGeneration对象
            for (ImageGeneration result : results) {
                // 获取当前结果中图片的URL
                String imageUrl = result.getOutput().getUrl();
                // 将URL添加到imageUrls列表中
                imageUrls.add(imageUrl);
            }
        }
        // 返回包含所有生成图片URL的列表
        return imageUrls;
    }

    /**
     * 文字生成视频
     * @param videoQuery 视频查询对象，包含生成视频所需的各种参数
     * @return 生成的视频的URL
     */
    @Override
    @SneakyThrows
    public String video(@NotNull VideoQuery videoQuery) {
        // 创建VideoSynthesis对象，用于调用阿里百炼视频合成服务
        VideoSynthesis vs = new VideoSynthesis();

        //视频比例
        String szie = videoQuery.getWidth() + "x" + videoQuery.getHeight();
        //描述
        String prompt = "根据"  + videoQuery.getPrompt() + "生成一个视频比例为" + szie + (videoQuery.getAddMusic() ? "并且添加背景音乐" : "");
        // 构建视频合成参数
        VideoSynthesisParam param =
                VideoSynthesisParam.builder()
                        // 指定使用的模型
                        .model(dashScopeConfig.getModelTextVideo())
                        // 设置视频描述文本
                        .prompt(prompt)
                        // 设置视频分辨率
                        .size("1280*720")
                        // 设置key
                        .apiKey(dashScopeConfig.getApiKey())
                        // 设置视频时长为5秒
                        .duration(5)
                        .build();

        // 调用阿里百炼视频合成服务，获取生成的视频URL
        String videoSrc = vs.call(param).getOutput().getVideoUrl();
        log.info("视频合成成功，视频地址为：{}", videoSrc);
        // 保存生成的视频
        saveVideo(videoSrc, videoQuery, "文生");
        // 返回生成的视频URL
        return videoSrc;
    }

    /**
     * 保存生成的视频
     * @param content
     * @param videoQuery
     */
    @Transactional(rollbackFor = Exception.class)
    private void saveVideo(String content, @NotNull VideoQuery videoQuery, String type) {
         //获取当前用户
        Long userId = getUserId();
         //创建视频对象
        AiVideo aiVideo = new AiVideo();
        aiVideo.setUserId(userId);
        aiVideo.setVideoSrc(content);
        aiVideo.setDescription(videoQuery.getPrompt());
        aiVideo.setType(type);
        aiVideo.setImage(videoQuery.getImage());
        aiVideo.setCreateTime(new Date());
        //保存视频
        aiVideoMapper.insert(aiVideo);
    }

    /**
     * 图片生成视频
     * @param videoQuery 视频查询对象，包含生成视频所需的各种参数
     * @return 生成的视频的URL
     */
    @Override
    @SneakyThrows
    public String imgVideo(@NotNull VideoQuery videoQuery) {
        // 创建VideoSynthesis对象，用于调用阿里百炼视频合成服务
        VideoSynthesis vs = new VideoSynthesis();

        //描述
        String prompt = "根据"  + videoQuery.getPrompt()  + (videoQuery.getAddMusic() ? "并且添加背景音乐" : "");
        // 构建视频合成参数
        VideoSynthesisParam param =
                VideoSynthesisParam.builder()
                        // 指定使用的模型
                        .model(dashScopeConfig.getModelImageVideo())
                        // 设置视频描述文本
                        .prompt(prompt)
                        .imgUrl(videoQuery.getImage())
                        // 设置视频分辨率
                        .size("1280*720")
                        // 设置key
                        .apiKey(dashScopeConfig.getApiKey())
                        // 设置视频时长为5秒
                        .duration(5)
                        .build();

        // 调用阿里百炼视频合成服务，获取生成的视频URL
        String videoSrc = vs.call(param).getOutput().getVideoUrl();
        log.info("视频合成成功，视频地址为：{}", videoSrc);
        // 保存生成的视频
        saveVideo(videoSrc, videoQuery, "图生");
        // 返回生成的视频URL
        return videoSrc;
    }

    /**
     * 视频生成视频
     * @return
     */
    @Override
    @Transactional(readOnly = true)
    public List<AiVideo> videoList() {
        //获取用户id
        Long userId = getUserId();
        //从数据库获取视频列表
        List<AiVideo> aiVideoList = aiVideoMapper.selectByUserId(userId);
        return aiVideoList;
    }

    /**
     * 删除视频
     * @param id
     */
    @Override
    public void deleteVideo(Long id) {
        //获取当前用户id
        Long userId = getUserId();
        //删除视频
        aiVideoMapper.deleteVideo(id, userId);
    }

    /**
     * 从缓存里面获取对话历史记录
     * @param userId
     */
    private void loadConversationHistoryFromCache(Long userId) {
        // 从缓存中获取对话历史
        String cacheKey = "conversationHistory:" + userId;
        List<Message> cachedHistory = (List<Message>) redisTemplate.opsForValue().get(cacheKey);
        // 判断缓存中是否存在对话历史
        if (cachedHistory != null) {
            // 如果缓存中存在对话历史，直接使用
            conversationHistory = cachedHistory;
        } else {
            // 如果缓存中不存在，从数据库加载对话历史
            loadConversationHistory(userId);
        }
    }

    /**
     * 保存用户的对话历史记录
     * @param userContent
     * @param botResponse
     * @param userId
     */
    private void saveConversationHistory(String userContent, String botResponse, Long userId) {
        //创建对话历史记录
        AiAnswer aiAnswer = new AiAnswer();
        aiAnswer.setUserId(userId);
        aiAnswer.setUserContent(userContent);
        aiAnswer.setAiContent(botResponse);
        aiAnswerMapper.insert(aiAnswer);
    }

    /**
     * 从数据库加载对话历史
     *
     * @param userId 用户ID
     */
    private void loadConversationHistory(Long userId) {
        // 从数据库中获取用户的对话历史
        List<AiAnswer> UserAnswer = aiAnswerMapper.getAiAnswer(userId);
        if(UserAnswer == null || UserAnswer.size() == 0)
        {
            return;
        }
        // 清空当前对话历史
        conversationHistory.clear();
        //循环遍历
        for (AiAnswer aiAnswer : UserAnswer) {
            // 构造用户消息
            Message userMessage = Message.builder()
                    .role(Role.USER.getValue())
                    .content(aiAnswer.getUserContent())
                    .build();

            // 将用户消息添加到对话历史中
            conversationHistory.add(userMessage);

            // 构造模型回复消息
            Message botMessage = Message.builder()
                    .role(Role.ASSISTANT.getValue())
                   .content(aiAnswer.getAiContent())
                    .build();
            // 将模型回复添加到对话历史中
            conversationHistory.add(botMessage);
        }
        // 更新缓存中的对话历史
        updateConversationHistoryCache(userId);
    }

    /**
     * 更新对话历史缓存
     * @param userId
     */
    private void updateConversationHistoryCache(Long userId) {
        String cacheKey = "conversationHistory:" + userId;
        redisTemplate.opsForValue().set(cacheKey, conversationHistory, 1, TimeUnit.DAYS);
    }


    /**
     * 获取当前用户id
     * @return
     */
    private Long getUserId() {
        LoginUser loginUser = LoginUserHolder.getLoginUser();
        //判断是否存在
        if(loginUser == null)
        {
            throw new BaseException(ResultCodeEnum.APP_LOGIN_AUTH);
        }
        String phone = loginUser.getPhone();
        UserInfo userInfo = userInfoMapper.selectByPhone(phone);
        return userInfo.getUserId();
    }

    /**
     * 重置对话历史
     */
    public void resetConversation() {
        conversationHistory.clear();
    }
}
